﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.OracleClient;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using DevExpress.Xpo;
using LprMiddleWare.DAL;
using LprMiddleWare.Model;
using LprMiddleWare.ServiceReference1;
using LprMiddleWare.Services;

namespace LprMiddleWare
{
    class UploadService
    {
        private const int MaxFileSize = 300 * 1024;
        private readonly Action<string> _uilogger;
        private XmlDocument _xmlTemplate;
        private ConcurrentBag<LicensePlate> _licensePlates
            = new ConcurrentBag<LicensePlate>();

        private Thread _thread;
        private Services.IUploader _uploader;
        private NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();

        public UploadService(Action<string> Logger)
        {
            _uilogger = Logger;
            _xmlTemplate = new XmlDocument();
            _xmlTemplate.Load("UploadTemplate.xml");

            var service = new dyService();
            service.Url = Settings.LoadDefault().WeiZhangDataUrl;

            _uploader = service;

            _thread = new Thread(Start);
            _thread.IsBackground = true;
            _thread.Start();

        }


        private void Start()
        {
            var setting = Settings.LoadDefault();
            while (true)
            {
                using (var dl = Helper.ConnectToDbUntilSuccess(setting.DbServer, setting.DbUserName, setting.DbPassWord))
                {
                    while (true)
                    {
                        if (!_licensePlates.IsEmpty)
                        {
                            LicensePlate licensePlate;
                            if (_licensePlates.TryTake(out licensePlate))
                            {
                                if (!licensePlate.IsSpeeding || !IsValidRecord(licensePlate))
                                {
                                    continue;
                                }

                                Lane lane = null;
                                try
                                {
                                    using (var session = new Session(dl))
                                    {
                                        lane = Repository.Instance.GetLane(session, licensePlate.DeviceId,
                                                                           licensePlate.Direction,
                                                                           licensePlate.LaneNo.ToString("d2"));
                                    }

                                }
                                catch (OracleException ex)
                                {
                                    _licensePlates.Add(licensePlate);
                                    break;
                                }

                                if (lane == null)
                                {
                                    var msg = string.Format("无法查询到车道信息{0}{1}{2}，无法上传违章数据", licensePlate.DeviceId,
                                                            licensePlate.Direction, licensePlate.LaneNo.ToString("d2"));
                                    LogMessage(msg);
                                    _logger.Error(msg);
                                    continue;
                                }

                               
                                try
                                {
                                    var doc = ConvertToXml(licensePlate, lane, setting.UploadLry);
                                    var resultXml = _uploader.Upload(doc, setting.UploadKey, setting.UploadDwbm);
                                    var result = ParseResult(resultXml);
                                    var msg = string.Format("上传违章超速数据成功 车牌号：{0}", licensePlate.LicenseNumber);
                                    if (result.Item1 == "0")
                                    {
                                        msg = string.Format("上传违章超速数据失败: {0}, 车牌号：{1} ", result.Item2, licensePlate.LicenseNumber);
                                        _logger.Error(msg);
                                    }

                                    LogMessage(msg);
                                }
                                catch (Exception ex)
                                {
                                    LogMessage("上传违章超速数据发生异常: " + ex.Message);
                                    _logger.ErrorException("上传违章超速数据发生异常", ex);
                                }
                            }

                        }
                        else
                        {
                            _uilogger("没有违章超速数据需要上传，等待10秒");
                            Thread.Sleep(10000);
                        }
                    }
                }
            }

        }

        private bool IsValidRecord(LicensePlate licensePlate)
        {
            if (licensePlate.Images.Count < 2)
            {
                return false;
            }

            var fi = new FileInfo(GetAbsolutePath(licensePlate.Images[0]));
            if (fi.Length > MaxFileSize)
            {
                return false;
            }

            fi = new FileInfo(GetAbsolutePath(licensePlate.Images[1]));
            if (fi.Length > MaxFileSize)
            {
                return false;
            }

            return true;
        }

        private Tuple<string, string> ParseResult(string resultXml)
        {
            const string resultTag = "<result>";
            const string messageTag = "<message>";
            const string messageEndTag = "</message>";
            var i1 = resultXml.IndexOf(resultTag, StringComparison.Ordinal);
            var i2 = resultXml.IndexOf(messageTag, StringComparison.Ordinal);
            var i3 = resultXml.IndexOf(messageEndTag, StringComparison.Ordinal);
            var res = resultXml.Substring(i1 + resultTag.Length, 1);
            var msg = resultXml.Substring(i2 + messageTag.Length, i3 - i2 - messageTag.Length);
            return new Tuple<string, string>(res, msg);
        }

        public bool Upload(LicensePlate licensePlate)
        {
            if (_licensePlates.Count < 100)
            {
                _licensePlates.Add(licensePlate);
            }
            else
            {
                LogMessage("超速违章数据上传队列已满，请检查远端上传web服务是否工作正常!!");
            }

            return true;

        }

        private string ConvertToXml(LicensePlate licensePlate, DAL.Lane lane, string lry)
        {
            var root = _xmlTemplate.DocumentElement["peccancydzy"];
            root["hphm"].InnerText = licensePlate.LicenseNumber;
            //root["hpzl"].InnerText = PlateTypeConverter.Convert(licensePlate.PlateType);
            root["wfsj"].InnerText = licensePlate.CaptureTime.ToString("yyyy-MM-dd HH:mm:ss");
            root["wfdd"].InnerText = lane.KKMCDM;
            root["wfddmc"].InnerText = lane.KakouName;
            root["wfxw"].InnerText = "1302";
            root["cjjg"].InnerText = lane.SSDWDM;
            root["lry"].InnerText = lry;
            var p = GetAbsolutePath(licensePlate.Images[0]);
            var bytes = File.ReadAllBytes(p);
            root["zjwj1"].InnerText = Convert.ToBase64String(bytes);
            if (licensePlate.Images.Count >= 2)
            {
                p = GetAbsolutePath(licensePlate.Images[1]);
                if (File.Exists(p))
                {
                    var b = File.ReadAllBytes(p);
                    root["zjwj2"].InnerText = Convert.ToBase64String(b);
                }
            }

            root["clfx"].InnerText = lane.DirectionName;
            root["cdxx"].InnerText = licensePlate.LaneNo.ToString(CultureInfo.InvariantCulture);
            root["csscz"].InnerText = licensePlate.Speed.ToString(CultureInfo.InvariantCulture);
            root["csxzz"].InnerText = licensePlate.SpeedLimit.ToString(CultureInfo.InvariantCulture);
            root["cjfs"].InnerText = "2";

            return _xmlTemplate.OuterXml;


        }

        private void LogMessage(string msg)
        {
            if (_uilogger != null)
            {
                _uilogger(msg);
            }
        }

        private string GetAbsolutePath(string subPath)
        {
            return Path.Combine(Settings.LoadDefault().TargetDirectory, subPath);
        }
    }
}
